
#ifndef MEMORY_H
#define MEMORY_H

template<class T> class TypeList
{
private:
	static const T* mpListHead;
	
	const T* mpNext;
	const T* mpPrev;

protected:
	
	TypeList()
	{
		//add to list, at front instead of walking list
		if(mpListHead)
			mpListHead->mpPrev = this;
		mpListHead = this;
		mpPrev = 0;
	}

	~TypeList()
	{
		//remove from list
		//list head edge case
		if(this == mpListHead)
		{
			mpListHead = mpNext;
			mpNext->mpPrev = 0;
		}//common case
		else if(mpPrev)
		{
			mpPrev->mpNext = mpNext;

			//list tail edge
			if(mpNext)
				mpNext->mpPrev = mpPrev;
		}
	}


public:
	T* GetTypeList() {return mpListHead;}
};


class Allocator
{
public:
	typedef int ID_t;
private:
	Allocator* mpParent;
	ID_t mID;
	
protected:
	Allocator(ID_t id, Allocator* pParent) 
		: mpParent(pParent)
		, mID(id)
	{	}

#ifdef ENABLE_MEM_STATS
	class Stats
	{
		u32 mNumAllocs;
		u32 mNumOutstandingAllocs;
		u32 mRequested;
		u32 mAllocated;

	public:
		void OnAlloc(void* p, size_t requested, size_t allocated)
		{
			++mNumAllocs;
			++mNumOutstandingAllocs;
			mRequested += requested;
			mAllocated += allocated;
		}
		void OnDealloc(void* p)
		{
			--mNumOutstandingAllocs;
		}
	}
	Stats mStats;
#endif

public:
	//some ground rules - allocate(0) returns NULL and deallocate(NULL) is a no-op
	virtual void* allocate(size_t sz)=0;
	virtual void deallocate(void* p)=0;

	Allocator* GetParent() { return mpParent; }
};

//declare in-place news
void* operator new(size_t sz, Allocator& pAlloc);
void* operator new(size_t sz, Allocator* pAlloc);

class StackAllocator : public Allocator
{
private:
	char* mBase;
	char* mAlloc;
	char* mEnd;

public:

	StackAllocator(ID_t id, Allocator* pParent, size_t sz) 
		: Allocator(id, pParent)
	{
		//grab space from parent
		mAlloc = static_cast<char*>(pParent->allocate(sz));
		mBase = mAlloc;
		mEnd = mBase + sz;
	}	

	void* allocate(size_t sz) 
	{
		if(mBase + sz < mEnd)
		{
			void* r = mBase;
			mBase += sz;
			return r;
		}
		return 0;
	}
	void deallocate(void* p) { 	 }

	void reset()
	{
		mBase = mAlloc;
	}
};

typedef unsigned int uint;

//shims are virtual pools, they track allocation made through them but pass all actual allocation on to thier parent.
class Shim : public Allocator
{
public:
	Shim(ID_t id, Allocator* mpParent) : Allocator(0, mpParent)
	{	}
	
};

#endif